package com.operate.api.app.pay.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.operate.api.app.balance.dao.AppBalanceDao;
import com.operate.api.app.balance.domain.po.AppBalancePO;
import com.operate.api.app.message.dao.AppMessageDao;
import com.operate.api.app.message.domain.po.AppMessagePO;
import com.operate.api.app.pay.domain.vo.ApplePayVO;
import com.operate.api.app.pay.domain.vo.RechargeRVO;
import com.operate.api.app.pay.domain.vo.RechargeVO;
import com.operate.api.app.pay.service.IPayService;
import com.operate.api.app.user.dao.AppUserDao;
import com.operate.api.app.user.domain.po.AppUserPO;
import com.operate.api.base.R;
import com.operate.api.base.Type;
import com.operate.api.operate.meal.dao.PackageDao;
import com.operate.api.operate.meal.domain.po.PackagePO;
import com.operate.api.operate.order.dao.OrderRechargeDao;
import com.operate.api.operate.order.domain.po.OrderRechargePO;
import com.operate.exception.BusinessException;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;


@Service
@Transactional
@Slf4j
public class PayServiceImpl implements IPayService {

//    private  static final  String A_LI_PAY_APP_ID="2021004124696245";
//    private  static final  String A_LI_PAY_APP_PRIVATE_KEY="MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCI2ovlIvyA/I1N78FSS4jnHLrAKGgfi/EWWi12t55VoXXfh0R4ZZqf5b08L6WX/blRKo5/6VeDptKhV7dcSLwgTkJCY9cwyg8g3zHpEsItUsJXdlzfNLRR28/xLTqWYI+70PPcY+Wmua2CN/Ks4pTHQURPcqnrKrGV2MZv0OgiuP8ElS4SAN3mOxrPjZkHO82OrR/exPc+UV4/mPsjKuWxqQq2lEbGp8TLkWUelD96Mh4aQEiWWuRH5LgAtYfuVqYaikG4RTdfJXVLaz3JxllAsZeylpIO4/XkQpZB4EchB+2rgkUItKwvUhgZI/MPfE5uVXZThikN7U01tfxMgGB3AgMBAAECggEAXzpL7Ca7M3oJTXkOuZgL7F2maX30bjcvjFE1n41HpOhUIDV85JY20RrI4e95t9h6skr9m24gUmCr4k8qLRIDrismmhHlNHL1sfb9QOSnr2gOCVQ4bay76NYezQCe6vLIMXXFqs7sh2ZeoOUTfU+xHTGCOhJcwGIV7mJIOphQX4/7EjtrfmxDqMFii8gt08U8GIWFowvqguJAK93xFWeEyZG6ReZkYKkRsCSncudc5gbio81CJlUvbRLjNxOpkAuEtLwi8Jxd/ieZu+oqQqZXrhDkzjEmfyuGi32U3ysl9eOWJ/DfLJ6HiusvDR0SaLYQF6qCgrUXeh77pmHTkwVr6QKBgQDQQsilNoM1ZwDZBFjM38if9ZdRKaLa5VHkQTOCMiZTOwENxrXQ1X7BOOTGndP8BVvksAMG8GrO3Kj5/z54QvBArSdNGxYxzc4RHy7Dgr4tsTzcpFn6XKgvsaUDh8xXOp41eda9+lJUj8LgMdn0919tx5BFM/J4Y1iXQhttYfW7fQKBgQCoOW3VZo3O6UOLwizmt99SDfPfOEJ/mp9/168UP0krh+STxF1t1eoiIe7hKX5GpfxU6wjAiULnR1lbuMv/fKpvaw7JOjaI+aD0EhO+cIwVdnMR2/dwhyMjLrDcE5Cxyk1hqAolL03pyhWh1OjBXHTfc57sK2J6y+Dq5Fq227dGAwKBgQDMMX7LRkyVkp2pKnLqxUvPUpv/jyRHHWsSsr8PG56qIoMg/8EKthlm2CKvftX3F0YHTnBZYGZI1t+y5olYnsEzmNKc7j7vrAssjHdsaIeRA2NaLqauLCUXRkU11fMLX8T5R7G+aW5JzP7UlOxQHC9r0qxovcsyMK4O+FkuAUtPfQKBgB0i7UIT5CXdQwS22f4QBM76ea3E2ceuKUgEPF++Ylb2z4FEdoYqkcXdqLk47ZUg9KZkmvx2Ca9zLSf0xuh2WDK6ETKLMZzh153Ob7sBVVH2VRHXznCgB1b1pE5J2Trh9ise5rrwCYefp8WC0dmDwP5e0TzIeuMX4tnsOUYIoiKvAoGBAJdN8wYZrwBIoVU5856oHp+UpFXgIPW0qGzXR4lkcWYnOj39aP5+ekiO7bMbsh3ddWocEBiSU+0WTDP4nuFVz3BuaNmMcM12aKUmfvNyBDYL9bSIJ/ClBgNfS4hS2UJaYrydSH8hpGbjzvIHbBF2qXiaoPJLQgRFWmJMcjoPxPR0";
//    private  static final  String A_LI_PAY_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZfKE2495fD5tSHmGM0pHgydKIEq4k6XvaELFr2/NvYiz7d7AW6SdmUUNLQhFHz5szWkRtJQP5ZxmGd87EVruQ6p7An0uKXCVMeQtv7Qki0IJCUzttpNG072dihHX6jRtUpSemDDolruH0Z7x8luN22olWIhAoAY9Mxrmzcrgh9w7NlTRUY4gaQh1hG9+r7Q8JUdhafCrcQrJc8lZMm0H5CPJnP1n0xzZYVVH1b3jPcPmx628jO6oflFWpCHwFPm5JOs4zgbqH9QBRs9t6oVuIxxnzxzdDa0lAfooeJ9SszBAyB8psPrUcBxgNGhCe9JTOfQ49sKjQqLHqkcv9bGzQIDAQAB";
    //    private  static final  String A_LI_PAY_APP_ID="2021004126646166";
//    private  static final  String A_LI_PAY_APP_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGwnIaeypUI2aOCt+v2JIBf1jFISRsA5mW6jNxn3933f9xQKlcjasgr4x0LIpY7hL6myubYTs1rlNwqqSIabF/VON4iQtqRlJZ3ISJwTaXiC9Yqr5Jt+fOBz7lJxRZIsuwQaQ2lYd7DQ8errXssnbT/jyt20KNPnEp3pR160np63bfoflnsLZ/Ygjimzf5a5zg/4Ayv5BElAUpcbr+f9UlKl0DQW9a6BSEqSPuxJ5TkUpHukpJ6Yi0VrUi122/3X8MdB2jzRo1Sk1Y1KHemSYKX40Xzx859m79rIE5xdatI4T+Uu8YiHiwG6qC/XU8W1lIFKxYrLzsuHoev9V7uyZJAgMBAAECggEACXiVCGNroCo0xPriqbsw18YZeRFRO/4sxzyCjRPGo6gIke8XeBfE1TFBT9DpkEJ7Nv283NjCjo1H8/0qPyQeg3J14jzPfpKeqw4iioP30EKUAUlOwmOYeRRtSTGr7m/RnPugDO4JbY6HZ4Kj6pTIYTHXFej5DnA7B9RK3tbAhR4afzYnKL3TcPk9L+3/GYPiNYDN3P24vmJvtr4/Hcewje2MuqVpV5CZSS/M29fDBRzrcWMMlZdHFZNfautrhGz4U+KJlFsLWER7y3rcyw+TaxNFofzyatbsVtk9FftTWngCEB0viyUYuJEas4X9meLf2cKsy7Pym6hxzFU8DMESeQKBgQDtnyzdOUMSSXNAdnJTtKfQtMVIu3SV4qvk3fi9AwoggQmMOJd5GzVaPXczLyoNBM9vHdfHWD1Sa1XyhlELSxvaPtVr0T+6e3YVbfmR+FO5oA/riIskB8keF+AdWHP5CK8ymn3LrxgfdWpSh7ltpcat4B7MSjh9OK9awWaliV8J+wKBgQCRLqLGpmz23mma5LOsKQgQkeHE3z/87ucCU8/QvSpuocm9xcPc2ag7PCFDlP7JD59BMNxJxcW9vbHknCUYiy77kjZ09/pwGsT8cv1ItMjl/MfdvOt50YFJdnCv9NxoRQEFIJ93pvxOPkJyg4I3ZMFCU0Fuw5o/gLuQQmPyz0hBiwKBgQDWfyRJgkIoRMNTwlgLdX0y6atYr1ZbYqUWUMUTIaZHlxOeTwt01/m+PtPWEVIdNGVngYHhwaaBOsD3zwVjc2ZuCOAwlk+3r3D1gTOS753sZy9XxwcK/DgxAQ5ejxUJDSzROiIp9iGJbD0QyNG6x7VkCXbjpG//oWaxPvnAnhN7dwKBgCKlloMBxI9FlL46RgaX5CzQI6jv/j1GZirQBZAzFKVCRvra71sNNnCscOPH8uXYrJDKMEgKwp39Xy7HdLLexF+VDRns8/885DW622c2fZslMC1ioG955/i4Izxamx7nGM84cdYEK8IgaYsah0Dg8p35cGwWkgEFn71VmrSfcwbxAoGAbMaHMfuNm3+ZxVzDEunWyv6vqXrIaSY3K9nNPQkGhrA3d7gxpL04Z+4xvaHrTL5UKkwLfsd2UzlqTnX3hTPKiYhLnCj7qAE5YnEVCn5jsoRrG01rzwuebBMNoU0UeFSMb8HCkh5oo6riC2E3zyHWyhvP3y1z65Xd9m6VQvpsK18=";
//    private  static final  String A_LI_PAY_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZfKE2495fD5tSHmGM0pHgydKIEq4k6XvaELFr2/NvYiz7d7AW6SdmUUNLQhFHz5szWkRtJQP5ZxmGd87EVruQ6p7An0uKXCVMeQtv7Qki0IJCUzttpNG072dihHX6jRtUpSemDDolruH0Z7x8luN22olWIhAoAY9Mxrmzcrgh9w7NlTRUY4gaQh1hG9+r7Q8JUdhafCrcQrJc8lZMm0H5CPJnP1n0xzZYVVH1b3jPcPmx628jO6oflFWpCHwFPm5JOs4zgbqH9QBRs9t6oVuIxxnzxzdDa0lAfooeJ9SszBAyB8psPrUcBxgNGhCe9JTOfQ49sKjQqLHqkcv9bGzQIDAQAB";
//    private  static final  String A_LI_PAY_NOTIFY_URL="http://220.200.155.28:20805/api/pay/a_callback";
//    private  static final  String A_LI_PAY_NOTIFY_URL="http://api-app.yujuyi.com/api/pay/a_callback";
    @Value("${a.li.pay.app.id}")
    private  String A_LI_PAY_APP_ID;
    @Value("${a.li.pay.private.key}")
    private  String A_LI_PAY_APP_PRIVATE_KEY;
    @Value("${a.li.pay.public.key}")
    private  String A_LI_PAY_PUBLIC_KEY;
    @Value("${a.li.pay.notify.url}")
    private  String A_LI_PAY_NOTIFY_URL;



    @Value("${wx.pay.app.id}")
    private  String WX_PAY_APP_ID;
    @Value("${wx.pay.merchant.id}")
    private  String WX_PAY_MERCHANT_ID;
    @Value("${wx.pay.private.key}")
    private  String WX_PAY_PRIVATE_KEY;
    @Value("${wx.pay.v3.key}")
    private  String WX_PAY_V3_KEY;
    @Value("${wx.pay.serial.no}")
    private  String WX_PAY_SERIAL_NO;
    @Value("${wx.pay.notify.url}")
    private  String WX_PAY_NOTIFY_URL;





    private final ReentrantLock lock = new ReentrantLock();
    @Autowired
    private PackageDao packageDao;
    @Autowired
    private OrderRechargeDao rechargeDao;
    @Autowired
    private AppUserDao userDao;
    @Autowired
    private AppBalanceDao balanceDao;

    @Autowired
    private AppMessageDao appMessageDao;

    @Override
    public RechargeRVO addRecharge(RechargeVO rechargeVO) {
        PackagePO packagePO=packageDao.selectByPrimaryKey(rechargeVO.getMealId());
        if(packagePO==null){
            throw new BusinessException(Type.NOT_FOUND_ERROR.getCode(),"充值套餐信息不存在！");
        }
        if(packagePO.getPackageState()!=1){
            throw new BusinessException(Type.PARAM_VALIDATE_FAIL.getCode(),"充值套餐已被禁用！");
        }
        AppUserPO appUserPO= userDao.selectByPrimaryKey(StpUtil.getLoginId());
        if(appUserPO==null){
            throw new BusinessException(Type.NOT_FOUND_ERROR.getCode(),"用户信息不存在！");
        }
        String orderId= DateUtil.format(new Date(),"yyyyMMddHHmmss")+ RandomUtil.randomInt(1000,9999);
        OrderRechargePO orderRechargePO=new OrderRechargePO();
        orderRechargePO.setOrderType(rechargeVO.getPayType());
        orderRechargePO.setOrderMoney(packagePO.getPackagePrice());
        orderRechargePO.setOrderNum(new BigDecimal(packagePO.getPackageNum()).add(new BigDecimal(packagePO.getPackageGive())).longValue());
        orderRechargePO.setOrderState(1);
        orderRechargePO.setUserId(appUserPO.getId());
        orderRechargePO.preInsert();
        orderRechargePO.setId(orderId);
        orderRechargePO.setRemarks(packagePO.getPackageName());
        rechargeDao.insertSelective(orderRechargePO);
        RechargeRVO rechargeRVO=new RechargeRVO();
        rechargeRVO.setOrderId(orderRechargePO.getId());
        if(rechargeVO.getPayType()==1){
            rechargeRVO.setPayText(al_pay(orderRechargePO.getOrderMoney(),packagePO.getPackageName(),orderId));
        }
        if(rechargeVO.getPayType()==2){
            rechargeRVO.setPayText(wx_pay(orderRechargePO.getOrderMoney(),packagePO.getPackageName(),orderId));
        }
        return rechargeRVO;
    }

    @Override
    public R getAppPay(String states, JSONObject job, String transactionID, HttpServletRequest request, ApplePayVO applePayVo) {
        if ("0".equals(states)) {
            String r_receipt = job.getString("receipt");
            JSONObject returnJson = JSONObject.parseObject(r_receipt);
            String in_app = returnJson.getString("in_app");
            JSONObject in_appJson = JSONObject.parseObject(in_app.substring(1, in_app.length() - 1));
            log.info(in_appJson.toJSONString());
            String transactionId = in_appJson.getString("transaction_id");
            //产品id
            String productId = in_appJson.getString("product_id");
            //苹果支付订单状态
            String in_app_ownership_type = in_appJson.getString("in_app_ownership_type");

            log.info(transactionId+"=="+transactionID);
            log.info(in_app_ownership_type+"==PURCHASED");
            //如果获取验证后的支付订单单号与app端传来的支付订单号一致并且状态为已支付状态则处理自己的业务
            if (transactionID.equals(transactionId) && in_app_ownership_type.equals("PURCHASED")) {
                 //  ===================处理自己的业务============================
                PackagePO packagePO=packageDao.selectByPrimaryKey(applePayVo.getPackageId());
                if(packagePO==null){
                    throw new BusinessException(Type.NOT_FOUND_ERROR.getCode(),"充值套餐信息不存在！");
                }
                if(packagePO.getPackageState()!=1){
                    throw new BusinessException(Type.PARAM_VALIDATE_FAIL.getCode(),"充值套餐已被禁用！");
                }
                AppUserPO appUserPO= userDao.selectByPrimaryKey(StpUtil.getLoginId());
                if(appUserPO==null){
                    throw new BusinessException(Type.NOT_FOUND_ERROR.getCode(),"用户信息不存在！");
                }
                String orderId= DateUtil.format(new Date(),"yyyyMMddHHmmss")+ RandomUtil.randomInt(1000,9999);
                OrderRechargePO orderRechargePO=new OrderRechargePO();
                orderRechargePO.setOrderType(3);
                orderRechargePO.setOrderMoney(packagePO.getPackagePrice());
                orderRechargePO.setOrderNum(new BigDecimal(packagePO.getPackageNum()).add(new BigDecimal(packagePO.getPackageGive())).longValue());
                orderRechargePO.setOrderState(2);
                orderRechargePO.setUserId(appUserPO.getId());
                orderRechargePO.preInsert();
                orderRechargePO.setId(orderId);
                orderRechargePO.setRemarks(packagePO.getPackageName());
                orderRechargePO.setOrderNo(transactionId);
                orderRechargePO.setOrderDate(orderRechargePO.getCreateDate());
                rechargeDao.insertSelective(orderRechargePO);

                appUserPO.setUserBalance(appUserPO.getUserBalance().add(new BigInteger(orderRechargePO.getOrderNum().toString())));
                appUserPO.setRechargeMoney(appUserPO.getRechargeMoney().add(orderRechargePO.getOrderMoney()));
                appUserPO.preUpdate();
                userDao.updateByPrimaryKeySelective(appUserPO);
                //添加用户钱包编号
                AppBalancePO appBalancePO=new AppBalancePO();
                appBalancePO.setOrderType(1);
                appBalancePO.setUserId(appUserPO.getId());
                appBalancePO.setOrderId(orderRechargePO.getId());
                appBalancePO.setOrderNum(new BigDecimal(orderRechargePO.getOrderNum()));
                appBalancePO.setOrderDesc("充值");
                appBalancePO.preInsert();
                balanceDao.insertSelective(appBalancePO);

                AppMessagePO appMessagePO=new AppMessagePO();
                appMessagePO.setMsgDesc("充值"+orderRechargePO.getOrderMoney()+"元，获取"+orderRechargePO.getOrderNum()+"来豆");
                appMessagePO.setMsgTitle("充值成功");
                appMessagePO.setMsgType(9);
                appMessagePO.setRelationId(orderRechargePO.getId());
                appMessagePO.preInsert();
                appMessagePO.setUserId(orderRechargePO.getUserId());
                appMessageDao.insertSelective(appMessagePO);

                JSONObject jsonObject= new JSONObject();
                jsonObject.put("verify_status",states);
                return new R();
            }
            JSONObject jsonObject= new JSONObject();
            jsonObject.put("verify_status",states);
            return new R(Type.APPLE_PAY_NO).setMessage("验证状态有问题").setData(jsonObject);
        }

        JSONObject jsonObject= new JSONObject();
        jsonObject.put("verify_status",states);
        return new R(Type.APPLE_PAY_NO).setMessage("receipt数据有问题").setData(jsonObject);
    }


//    public static void main(String[] args) {
//        String orderId= DateUtil.format(new Date(),"yyyyMMddHHmmss")+ RandomUtil.randomInt(1000,9999);
//        al_pay(new BigDecimal("0.01"),"测试充值",orderId);
//    }

    public  String al_pay(BigDecimal money, String desc, String orderId) {
        try{
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", A_LI_PAY_APP_ID, A_LI_PAY_APP_PRIVATE_KEY,AlipayConstants.FORMAT_JSON ,
                    AlipayConstants.CHARSET_UTF8, A_LI_PAY_PUBLIC_KEY, AlipayConstants.SIGN_TYPE_RSA2);
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest ();
            request.setNotifyUrl(A_LI_PAY_NOTIFY_URL);//异步接收地址，仅支持http/https，公网可访问
            /******必传参数******/
            JSONObject bizContent = new JSONObject();
            //商户订单号，商家自定义，保持唯一性
            bizContent.put("out_trade_no", orderId);
            bizContent.put("total_amount", money);
            bizContent.put("subject", desc);
            request.setBizContent(bizContent.toString());
            AlipayTradeAppPayResponse response =alipayClient.sdkExecute(request);
            return response.getBody();
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(Type.FAIL.getCode(),"支付宝下单失败！");
        }
    }

    public String wx_pay(BigDecimal money, String desc, String orderId)  {
        log.info("下单详情："+orderId+"::"+money+"("+money.multiply(new BigDecimal("100")).intValue()+")"+"::"+desc);
        try{
            // 加载商户私钥（privateKey：私钥字符串）
            PrivateKey merchantPrivateKey = PemUtil
                    .loadPrivateKey(new ByteArrayInputStream(WX_PAY_PRIVATE_KEY.getBytes("utf-8")));
            List<X509Certificate> certificates=null;
            // 加载平台证书（mchId：商户号,mchSerialNo：商户证书序列号,apiV3Key：V3密钥）
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(WX_PAY_MERCHANT_ID, new PrivateKeySigner(WX_PAY_SERIAL_NO, merchantPrivateKey)),WX_PAY_V3_KEY.getBytes("utf-8"));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(WX_PAY_MERCHANT_ID, WX_PAY_SERIAL_NO, merchantPrivateKey)
                    .withValidator( new WechatPay2Validator(verifier));
            CloseableHttpClient httpClient = builder.build();

            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid",WX_PAY_MERCHANT_ID)
                    .put("appid", WX_PAY_APP_ID)
                    .put("description", desc)
                    .put("notify_url", WX_PAY_NOTIFY_URL)
                    .put("out_trade_no", orderId);
            rootNode.putObject("amount")
                    .put("total", money.multiply(new BigDecimal("100")).intValue())
                    .put("currency","CNY");
            objectMapper.writeValue(bos, rootNode);
            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            JSONObject jsonObject=JSONObject.parseObject(bodyAsString);
            jsonObject.put("appId",WX_PAY_APP_ID);
            jsonObject.put("partnerId",WX_PAY_MERCHANT_ID);
            jsonObject.put("prepayId",jsonObject.getString("prepay_id"));
            jsonObject.put("packageValue","Sign=WXPay");
            jsonObject.put("nonceStr", IdUtil.getSnowflakeNextIdStr());
            Instant now = Instant.now();
            jsonObject.put("timeStamp", now.getEpochSecond());
            String signStr=WX_PAY_APP_ID+"\n"+
                    jsonObject.getString("timeStamp")+"\n"+
                    jsonObject.getString("nonceStr")+"\n"+
                    jsonObject.getString("prepayId")+"\n";
            log.info(signStr);
            Signature signature = Signature.getInstance("SHA256WithRSA"); // 创建签名对象
            signature.initSign(merchantPrivateKey); // 初始化签名对象，传入私钥
            signature.update(signStr.getBytes()); // 更新签名数据
            byte[] signBytes = signature.sign(); // 进行签名
            String signData = Base64.getEncoder().encodeToString(signBytes);
            jsonObject.put("sign", signData);
            return jsonObject.toJSONString();
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessException(Type.FAIL.getCode(),"微信下单失败！");
        }



    }





    @Override
    public void al_callback(HttpServletRequest request, HttpServletResponse response) throws IOException, AlipayApiException {
        log.info("支付宝异步通知");
        PrintWriter out = response.getWriter();
        if (lock.tryLock()) {
            try {
                Map<String, String> params = getStringStringMap(request);
                boolean signVerified = AlipaySignature.rsaCheckV1(params, A_LI_PAY_PUBLIC_KEY, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);
                if (!signVerified) {
                    log.error("验签失败");
                    out.print("fail");
                    return;
                }
                log.warn("=========== 在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱 ===========");
                // 通知ID
                String notifyId = new String(params.get("notify_id").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                // 通知时间
                String notifyTime = new String(params.get("notify_time").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //支付宝交易号
                String tradeNo = new String(params.get("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //付款金额
                String totalAmount = new String(params.get("total_amount").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //交易状态
                String tradeStatus = new String(params.get("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                //商户订单号,之前生成的带用户ID的订单号
                String outTradeNo = new String(params.get("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                /*
                 * 交易状态
                 * TRADE_SUCCESS 交易完成
                 * TRADE_FINISHED 支付成功
                 * WAIT_BUYER_PAY 交易创建
                 * TRADE_CLOSED 交易关闭
                 */
                log.info("tradeStatus:" + tradeStatus);
                if ("TRADE_FINISHED".equals(tradeStatus)) {
                } else if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    OrderRechargePO orderRechargePO=rechargeDao.selectByPrimaryKey(outTradeNo);
                    //判断充值状态是待支付 进入逻辑
                    if(orderRechargePO.getOrderType()==1){
                        opRechargeOrder(tradeNo, notifyTime, orderRechargePO);
                    }
                }
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
        out.print("success");
    }

    public static void main(String[] args) {
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber("1E63B34CC615F9FC29B741FD583A38169D640821")
                .nonce("OrRLnwgZZVAnVxnK77pJ4Top1zKtYqhH")
                .signature("B/cLURp6R46uApcD9iWfAsPoAfcm3xUOVFuUvcD+7F5yC1M37PpBuTNBrs4+a5xL+IOHwcZ1+5GEn1uo1654ha/g3QdhVCS2lY99Pd2YaJ7vLPxArw8+egv8M/ihe4S63GTFL2H5PCtR6dM7J+qxeRPZgibT/hdw5Z9eC6NPS4xoBB2htiAIxU39lPTgkVnlMzzurVFDGYbr1U8tTeQcNGrE7OSK3vaJcgsHMpJ5Nlqm92ymeOV9CqD6ptWOgyWlphn4Jm+XtWqrzhpfztsEzWA0QDtlrmUhlsgpUUv5vIqDO2PGs8epk7UJKgPnhfY2OwSz4Ld9Fb92n+uLjZWFdg==")
                .timestamp("1714057995")
                .body("{\"id\":\"bd0265de-3e23-58cd-8c81-ec69bd3f6b65\",\"create_time\":\"2024-04-25T23:13:14+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"TRANSACTION.SUCCESS\",\"summary\":\"支付成功\",\"resource\":{\"original_type\":\"transaction\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"/dqpV9jyZNgF8aP3CehyRTHyjGdPdFMLRJjb8U7Gk1gEifDxWQn0GjQw5PN3hnqzlmeEH97oLVxvXviGpWXZ/Lrm8smH99sTK8PF3c/0hdqUarrul69x9Zxk3yI2Ki8vqCoHHEVfdOE9BRQqMSCTDH6WcvK5rRzKa7zfHV8aY+g6ZdSxoNP5YdPKY86jLXvqIML1JjTN+jG3Gkkwh8tBM4x5sInheljNi7FrJFihrpvtHE6LlDee3BkKvsEjn9Pffei/ODEbXEMgfJPB1WvDpFAccQhe5HPHjQBKcYCKMlnf9eacDiOR53q9f7XdGYUtwnQHOa3MOjld1/Pv1DAS1CDH6BMnBwqni4f6piyLAXrHxSNbjX2ei2mNd67fB76ZMHFGSTt3rJ8DH1/7P19EtRxJYaxH/msEN3AGmin8SvaDziFiBolfWi0QwpfrIz4dbDnNw5XU/vaFdEwf0oiiL95Bd0rnmpYkkVlhXCwGGxv+ZwLbla6UyNQzLvc0inP2Nc3MpN5C1gslaszW0Nwer7C8DF0wtksZ5R1L5Spso+4L1mNnlMOcgP99B76a2jo=\",\"associated_data\":\"transaction\",\"nonce\":\"ShUIEQEyoTwl\"}}")
                .build();

        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId("1671391968")
                .privateKey("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCyiMTi2FmruGRg/wW0lmoGV3xbUG0ER3jMz0Ow8CYdVjmtHZ9zfJxRJaz56TNGZoOoLRc/vAyhN4Hl4Io90pOiPQzcYW8YBTIEbCcIDQ5xkMJgANiR/9OQ/2a/Zdqgo9lOlE3qgrbUbVOBTJWR0e48zBJJ/7kBu3/ywtDEHzwaRGGIPO9Oqr6T4qP+xQHleBsqwA+FJidhQOajmxHNp7DPKstXvJasJWHhtHY2O17uOYpQxOcIMeyU2HcixkGw5jg6UHeauGvVluu4FVEDrmNweWQkl+Pf6WSq3QmGQwNL/iSSkFyMZTCVmU6ge3VzgsTuo7ttRVnAgvRRi2l3HuE9AgMBAAECggEAArrIl9dK968oCbuccLhkApjP0+2U3R3ioO8CT/A8BPLOivELAQ8ErNDwphmEqSzkEmwuENFlOAnLOKKIOo2/qBla2vu6YRmjPCITLrJUaDQYZLNenEzXBT6Caaa7Av2+Us89qbo55WGOh0mOd95H0DImjW8VewtM139XBciceKJQeGSqHY8s1i9gWuMhQiND5PAQGHRQL/Tr+ZAFLamv83wFHMJB8Y1FRzUOlgwwFB+EiZliTrZ5+ueZEs3BCiGvTBCSeiHZagwT1A1rRiLyKm9dWoPeNo6CPhQATkde3ewbiKm8fNimVJ/6kMDTTG6P/hhQeAMw5pgVzXiZAZrRGQKBgQDfAEBeXGlruMHcEzgQjgG7GP8mPPyNGGw1voV8qL1uMfcCu7i3D0t5oTzzzkwdT5rlqOwvgYWpvXR40NihHZG0827pwREGH9lUGBMdxMxbg6BIsh5wWGUPV8JgjZIZISD0UgZiXFM3KkKguJdXJDGYQTG5I7UhK0Tlv3GUHPIKqwKBgQDM9AYlEqDGgB6ZWpB7fim4aqy4GImAqqe+DnmLhD8uYvVKtbmaKxqW4lx6+Ff5fgUuVZlhJWMDo2Du41h2MYxa+T7stlAizFp+jc5ApQW44bn911YB+9XitzGOVD0kFq/Zsy89fO/y9j7exc+qgfB9wUuKoo96CwbFGm4F1+vDtwKBgF4R/xVPKnF0qOKrgNUK8pP4gXmh9G+Yw90QF8N0cySPE0Il6k/etdoDOHEor1cWA6Op1KhdnQLzlrR4dUnR7WtF3Z3iAcpxmP4ugbHnGMXqCq1f5hNCVq9YN/j+/4h2Py6Rg3vusnPs8dpWxBDQhdNSfSU6eOgbFp9MWR8/7qKtAoGAZcl7k8XgmzTd/YOA5hQOXEx+Yx+sin42uKkvrB6N0lfLQsNl3i8yEWVyUJAuAPaZVB2nAxwyRIhLh9jZAjoxXq0SlzUkL2QWPWvn1ysd4Ggamvrq+Ck+XE5nCizEALxTsWbQO1VlReEN8E2FiUTnT01EWyHI5++5+QHbSoOlz5kCgYBl0m94YdZ/BBOFQjvq4v/xTvdwc4uedCwkXZ8T64m8GS8vupMGnjFPBFm8z6MhhQ2DmDvBgpmCt3k4C6fS7qXoPOi5UxlILrWYDWCikFBHfEJDtq94Iy6c7KbZooZRPHAWjylDGSFaKB2pjR8weccbnWWdBn6tTEi7lvY4F3YvNQ==")
                .merchantSerialNumber("464F6A677842B711A257327953270306020670F4")
                .apiV3Key("KnY5xNTsMmZwhOjZY0T9mIWdmlW3RSVK")
                .build();
        NotificationParser parser = new NotificationParser(config);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info(transaction.toString());
        System.out.println(transaction.getTradeState().toString());
        String outTradeNo=transaction.getOutTradeNo();
        String tradeNo= transaction.getTransactionId();
        String successTime=transaction.getSuccessTime();
        System.out.println(outTradeNo+"_"+tradeNo+"_"+successTime+"_"+DateUtil.parse(successTime));
    }

    @Override
    public void wx_callback(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信异步通知");
        try{
            String requestBody=getRequestBody(request);
            log.info(requestBody);
            // 获取回调通知中的签名
            String signature = request.getHeader("Wechatpay-Signature");
            // 获取回调通知中的时间戳
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            //证书序列号（微信平台）
            String serialNo = request.getHeader("Wechatpay-Serial");
            // 获取回调通知中的随机串
            String nonce = request.getHeader("Wechatpay-Nonce");
            log.info(signature+"_"+timestamp+"_"+serialNo+"_"+nonce);
            // 验证签名
            InputStream is = null;
            try {
                is = request.getInputStream();
                // 构造 RequestParam
                RequestParam requestParam = new RequestParam.Builder()
                        .serialNumber(serialNo)
                        .nonce(nonce)
                        .signature(signature)
                        .timestamp(timestamp)
                        .body(requestBody)
                        .build();
                // 如果已经初始化了 RSAAutoCertificateConfig，可以直接使用  config
                // 初始化 NotificationParser
                NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                        .merchantId(WX_PAY_MERCHANT_ID)
                        .privateKey(WX_PAY_PRIVATE_KEY)
                        .merchantSerialNumber(WX_PAY_SERIAL_NO)
                        .apiV3Key(WX_PAY_V3_KEY)
                        .build();
                NotificationParser parser = new NotificationParser(config);
                // 验签、解密并转换成 Transaction
                try {
                    // 以支付通知回调为例，验签、解密并转换成 Transaction
                    Transaction transaction = parser.parse(requestParam, Transaction.class);
                    log.info(transaction.toString());
                    if (!StringUtils.equals("SUCCESS", transaction.getTradeState().toString())) {
                        log.error("微信回调失败,JsapiPayController.payNotify.transaction：{}",transaction.toString());
                        //通知微信回调失败
                        response.getWriter().write("");
                        JSONObject result = new JSONObject();
                        result.put("code", "FAIL");
                        result.put("message", "失败");
                        // 返回结果给微信支付平台
                        response.getWriter().write(result.toString());
                    }
                    String outTradeNo=transaction.getOutTradeNo();
                    String tradeNo= transaction.getTransactionId();
                    String successTime=transaction.getSuccessTime();
                    OrderRechargePO orderRechargePO=rechargeDao.selectByPrimaryKey(outTradeNo);
                    //判断充值状态是待支付 进入逻辑
                    if(orderRechargePO.getOrderType()==2){
                        opRechargeOrder(tradeNo, successTime, orderRechargePO);
                    }
                    JSONObject result = new JSONObject();
                    result.put("code", "SUCCESS");
                    result.put("message", "成功");
                    // 返回结果给微信支付平台
                    response.getWriter().write(result.toString());
                } catch (ValidationException e) {
                    // 签名验证失败，返回 401 UNAUTHORIZED 状态码
                    log.error("sign verification failed", e);
                    JSONObject result = new JSONObject();
                    result.put("code", "FAIL");
                    result.put("message", "失败");
                    // 返回结果给微信支付平台
                    response.getWriter().write(result.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
                JSONObject result = new JSONObject();
                result.put("code", "FAIL");
                result.put("message", "失败");
                // 返回结果给微信支付平台
                response.getWriter().write(result.toString());
            }finally {
                is.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void opRechargeOrder(String tradeNo, String successTime, OrderRechargePO orderRechargePO) {
        orderRechargePO.setOrderState(2);
        orderRechargePO.setOrderDate(DateUtil.parse(successTime));
        orderRechargePO.setOrderNo(tradeNo);
        orderRechargePO.preUpdate();
        rechargeDao.updateByPrimaryKeySelective(orderRechargePO);
        //添加用户信息
        AppUserPO appUserPO = userDao.selectByPrimaryKey(orderRechargePO.getUserId());
        appUserPO.setUserBalance(appUserPO.getUserBalance().add(new BigInteger(orderRechargePO.getOrderNum().toString())));
        appUserPO.setRechargeMoney(appUserPO.getRechargeMoney().add(orderRechargePO.getOrderMoney()));
        appUserPO.preUpdate();
        userDao.updateByPrimaryKeySelective(appUserPO);
        //添加用户钱包编号
        AppBalancePO appBalancePO = new AppBalancePO();
        appBalancePO.setOrderType(1);
        appBalancePO.setUserId(appUserPO.getId());
        appBalancePO.setOrderId(orderRechargePO.getId());
        appBalancePO.setOrderNum(new BigDecimal(orderRechargePO.getOrderNum()));
        appBalancePO.setOrderDesc("充值");
        appBalancePO.preInsert();
        balanceDao.insertSelective(appBalancePO);
        AppMessagePO appMessagePO = new AppMessagePO();
        appMessagePO.setMsgDesc("充值" + orderRechargePO.getOrderMoney() + "元，获取" + orderRechargePO.getOrderNum() + "来豆");
        appMessagePO.setMsgTitle("充值成功");
        appMessagePO.setMsgType(9);
        appMessagePO.setUserId(orderRechargePO.getUserId());
        appMessagePO.setRelationId(orderRechargePO.getId());
        appMessagePO.preInsert();
        appMessageDao.insertSelective(appMessagePO);
    }


    public boolean verifySign(Map<String, String> resultMap, String apiKey) {
        String sign = resultMap.get("sign");
        resultMap.remove("sign");

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : resultMap.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        sb.append("key=").append(apiKey);

        String calculatedSign = DigestUtils.md5Hex(sb.toString()).toUpperCase();

        return sign.equals(calculatedSign);
    }

    /**
     * 读取请求数据流
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("读取数据流异常:{}", e);
        }
        return sb.toString();
    }

    private Map<String, String> getStringStringMap(HttpServletRequest request) throws UnsupportedEncodingException {
        request.setCharacterEncoding("utf-8");
        //获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<>(8);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Map.Entry<String, String[]> stringEntry : requestParams.entrySet()) {
            String[] values = stringEntry.getValue();
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(stringEntry.getKey(), valueStr);
        }
        return params;
    }


}